package com.cloud.gateway.filters;



import com.alibaba.fastjson.JSONObject;
import com.cloud.gateway.common.Api;
import com.cloud.gateway.common.CacheKey;
import com.cloud.gateway.common.Common;
import com.cloud.gateway.component.AuthServer;
import com.cloud.gateway.config.AuthConfig;
import com.cloud.gateway.domain.ServiceResult;
import com.cloud.gateway.domain.UserInfo;
import com.cloud.gateway.exception.BusinessException;
import com.cloud.gateway.handler.RouteXmlHandler;
import com.cloud.gateway.util.Base64Util;
import com.cloud.gateway.util.RedisUtil;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;

import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.net.URI;
import java.util.HashSet;


@Component
public class RouteFilter implements GatewayFilter {
    private static final Logger log = LoggerFactory.getLogger(RouteFilter.class);

    @Resource
    private RedisUtil redisUtil;

    @Resource
    AuthConfig authConfig;

    @Resource
    RouteXmlHandler routeXmlHandler;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
    {
        try{
            log.info("Begin Filter");
            //String ip = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
            ServerHttpRequest request = exchange.getRequest();
            URI reqUrl = request.getURI();
            String url = reqUrl.getPath();
            //获取请求体内容
            HttpHeaders headers = request.getHeaders();

            //获取请求体内容
            String cacheRequestContent = exchange.getAttribute("cachedRequestBodyObject");
            if(null != authConfig.getDoAuth() && authConfig.getDoAuth().equals("true"))
            {
                AuthServer authServer = new AuthServer(authConfig.getSk());
                boolean authResult = authServer.doAuth(redisUtil,cacheRequestContent,request.getMethodValue(),url,headers);
                if(!authResult)
                {
                    //代表鉴权未通过
                    throw new BusinessException("鉴权未通过",Api.CODE_ERROR_AUTH);
                }
            }

            HashSet<String> actionUrls = routeXmlHandler.getActionUrls();

            if(null != actionUrls && actionUrls.size() > 0)
            {
                if(actionUrls.contains(url)) {
                    //如果当前路由需要登陆，则进行登录验证逻辑
                    log.info(url + " 需要验证登录");

                    String sessionId = headers.containsKey("s")
                            ? String.valueOf(headers.get("s").get(0)):"";

                    UserInfo userInfo = doValidateLogin(sessionId, redisUtil);
                    if (null == userInfo){
                        throw new BusinessException("未登录",Api.CODE_ERROR_LOGIN);
                    }

                    String xEcsU = Base64Util.encodeToStr(JSONObject.toJSONString(userInfo));

                    ServerHttpRequest newRequest = exchange.getRequest().mutate()
                            .header("X-ECS-U",xEcsU)
                            .header("X-ECS-S",sessionId)
                            .build();
                    //将现在的request 变成 change对象
                    ServerWebExchange build = exchange.mutate().request(newRequest).build();
                    return chain.filter(build);
                }
            }
            return chain.filter(exchange);
        }
        catch (BusinessException exception)
        {
            ServiceResult serviceResult = new ServiceResult(exception.getCode(),exception.getMessage(),new JSONObject());
            return Common.jsonReturn(exchange,serviceResult);
        }
        catch (Exception e)
        {
            ServiceResult serviceResult = new ServiceResult(Api.CODE_ERROR,e.getMessage(),new JSONObject());
            return Common.jsonReturn(exchange,serviceResult);
        }
    }

    private UserInfo doValidateLogin(String sessionId , RedisUtil redisUtil)
    {
        if(!"".equals(sessionId))
        {
            String cacheKey = String.format(CacheKey.LOGIN_INFO,sessionId);
            if(redisUtil.hasKey(cacheKey))
            {
                Object content = redisUtil.get(cacheKey);
                String loginInfo = JSONObject.toJSONString(content);
                //System.out.println("logInfo :" + loginInfo);
                if(!"".equals(loginInfo)) {
                    return JSONObject.parseObject(loginInfo, UserInfo.class);
                }
            }
        }
        return null;
    }

}
